#include "../include/list.h"

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>

Status SequenceListInit( PSequenceList L )
{
    L->elem = ( ElemType * )malloc( LIST_INIT_SIZE * sizeof( ElemType ) );

    if ( L->elem == NULL ) {
        return ERROR;
    }

    L->length = 0;
    L->listsize = LIST_INIT_SIZE;
    return OK;
}

Status SequenceListDestory( PSequenceList L )
{
    free( L->elem );

    L->elem = NULL;
    L->length = 0;
    L->listsize = 0;

    return OK;
}

Status SequenceListClear( PSequenceList L )
{
    L->length = 0;
    memset( L->elem, 0, L->listsize * sizeof( ElemType ) );

    return OK;
}

BOOL SequenceListEmpty( PSequenceList L )
{
    if ( L->elem == NULL || L->length == 0 ) {
        return TRUE;
    }

    return FALSE;
}


int SequenceListLength( PSequenceList L )
{
    return L->length;
}

Status SequenceListGetElem( PSequenceList L, int i, ElemType *pElem )
{
    if ( i < 1 || i > L->length ) {
        return ERROR;
    }

    *pElem = L->elem[i - 1];

    return OK;
}

int SequenceListLocateElem( PSequenceList L, ElemType e, compare pFunc )
{
    int nCnt;

    if ( L == NULL || pFunc == NULL ) {
        return 1;
    }

    for ( nCnt = 0; nCnt < L->length; ++nCnt ) {
        if ( pFunc( &e, &( L->elem[nCnt] ) ) ) {
            return nCnt - 1;
        }
    }

    return 0;
}

Status SequenceListInsert( PSequenceList L, int i, ElemType e )
{
    ElemType *newbase	= NULL;
    ElemType *pInsert	= NULL;
    ElemType *pEnd		= NULL;

    if ( i < 1 || i > L->length + 1 ) {
        return ERROR;
    }

    if ( L->length >= L->listsize ) {
        newbase = ( ElemType * )realloc( L->elem,
                                         ( L->listsize + LISTINCREMENT ) * sizeof( ElemType ) );

        if ( newbase == NULL ) {
            return ERROR;
        }

        L->elem = newbase;
        L->listsize += LISTINCREMENT;
    }

    pEnd = &( L->elem[L->length - 1] );
    pInsert = &( L->elem[i - 1] );

    for ( ; pEnd >= pInsert; --pEnd ) {
        *( pEnd + 1 ) = *( pEnd );
    }

    *pInsert = e;
    ++L->length;
    return OK;
}

Status SequenceListDelete( PSequenceList L, int i, ElemType *pElem )
{
    ElemType *pDeleteElem	= NULL;
    ElemType *pEndElem		= NULL;

    if ( pElem == NULL || L == NULL ) {
        return PARAMERROR;
    }

    if ( i < 1 || i > L->length ) {
        return ERROR;
    }

    pDeleteElem = &( L->elem[i - 1] );
    *pElem = *pDeleteElem;
    pEndElem = &( L->elem[L->length - 1] );

    for ( ++pDeleteElem; pDeleteElem <= pEndElem; ++pDeleteElem ) {
        *( pDeleteElem - 1 ) = *( pDeleteElem );
    }

    --L->length;
    return OK;
}

Status SequenceListPriorElem( PSequenceList L,
                              ElemType cur_e,
                              ElemType *ppre_e )
{
    ElemType *pBegin = NULL;
    ElemType *pEnd = NULL;

    if ( L == NULL || ppre_e == NULL ) {
        return ERROR;
    }

    if ( L->length <= 2 ) {
        return ERROR;
    }

    pBegin = &( L->elem[1] );
    pEnd = &( L->elem[L->length - 1] );

    for ( ; pBegin <= pEnd; ++pBegin ) {
        if ( *pBegin == cur_e ) {
            *ppre_e = *( pBegin - 1 );
            return OK;
        }
    }

    return ERROR;
}

Status SequenceListNextElem( PSequenceList L,
                             ElemType cur_e,
                             ElemType *pnext_e )
{
    ElemType *pBegin = NULL;
    ElemType *pEnd = NULL;

    if ( L == NULL || pnext_e == NULL ) {
        return ERROR;
    }

    if ( L->length <= 2 ) {
        return ERROR;
    }

    pBegin = &( L->elem[0] );
    pEnd = &( L->elem[L->length - 2] );

    for ( ; pBegin <= pEnd; ++pBegin ) {
        if ( *pBegin == cur_e ) {
            *pnext_e = *( pBegin + 1 );
            return OK;
        }
    }

    return ERROR;
}

Status ListTraverse( PSequenceList L, visit pFunc )
{
    ElemType *pBegin = NULL;
    ElemType *pEnd = NULL;

    if ( L == NULL || L->length < 1 ) {
        return ERROR;
    }

    pBegin = &( L->elem[0] );

    for ( pEnd = &( L->elem[L->length - 1] ); pBegin != pEnd; ++pBegin ) {
        if ( !pFunc( pBegin ) ) {
            return ERROR;
        }
    }

    return OK;
}

void SequenceListUnion( PSequenceList La, PSequenceList Lb )
{
    int La_length = SequenceListLength( La );
    int Lb_Length = SequenceListLength( Lb );
    int nCnt;
    ElemType e;

    for ( nCnt = 1; nCnt < La_length; ++nCnt ) {
        SequenceListGetElem( Lb, nCnt, &e );

        if ( !SequenceListLocateElem( La, e, equal ) ) {
            SequenceListInsert( La, ++La_length, e );
        }
    }
}

BOOL equal( ElemType *e1, ElemType *e2 )
{
    if ( *e1 == *e2 ) {
        return TRUE;
    }

    return FALSE;
}

BOOL output( ElemType *e )
{
    if ( e == NULL ) {
        return FALSE;
    }

    printf( "%d", *e );
    return TRUE;
}

void SequenceListMerge( PSequenceList La,
                        PSequenceList Lb,
                        PSequenceList Lc )
{
    int LaCnt = 1, LbCnt = 1;
    int LcCnt = 0;

    ElemType ae;
    ElemType be;

    int La_length = SequenceListLength( La );
    int Lb_length = SequenceListLength( Lb );

    SequenceListInit( Lc );

    while ( LaCnt <= La_length && LbCnt <= Lb_length ) {
        SequenceListGetElem( La, LaCnt, &ae );
        SequenceListGetElem( Lb, LbCnt, &be );

        if ( ae <= be ) {
            SequenceListInsert( Lc, ++LcCnt, ae );
            ++La_length;
        } else {
            SequenceListInsert( Lc, ++LcCnt, be );
            ++Lb_length;
        }
    }

    while ( LaCnt <= La_length ) {
        SequenceListGetElem( La, LaCnt++, &ae );
        SequenceListInsert( Lc, ++LcCnt, ae );
    }

    while ( LbCnt <= Lb_length ) {
        SequenceListGetElem( La, LbCnt++, &be );
        SequenceListInsert( Lc, ++LcCnt, be );
    }
}

int SequenceListVisitAllElem( PSequenceList L, visit pCallBack )
{

    int nCnt;

    if ( L == NULL || pCallBack == NULL ) {
        return 1;
    }

    printf( "[" );

    for ( nCnt = 0; nCnt < L->length; ++nCnt ) {
        if ( !pCallBack( &( L->elem[nCnt] ) ) ) {
            return 1;
        }

        if ( nCnt != L->length - 1 ) {
            printf( "," );
        }
    }

    printf( "]\n" );

    return 0;
}
